package znet

import (
	"fmt"
	"strconv"
	"zinx/src/utils"
	"zinx/src/ziface"
)

type MsgHandle struct {
	Apis           map[uint32]ziface.IRouter //存放msgid对应的处理方法路由
	WorkerPoolSize uint32                    //业务worker池的size
	TaskQueue      []chan ziface.IRequest    //worker负责取任务的消息队列
}

func NewMsgHandle() *MsgHandle {
	return &MsgHandle{
		Apis:           make(map[uint32]ziface.IRouter),
		WorkerPoolSize: utils.GlobalObject.WorkerPoolSize,
		//1个worker对应一个消息queue,即该channel的缓冲长度
		//用来缓冲提供worker调用的Request请求信息，
		//worker会从对应的队列中获取客户端的请求数据并且处理掉。
		TaskQueue: make([]chan ziface.IRequest, utils.GlobalObject.WorkerPoolSize),
	}
}

// SendMsgToTaskQueue 将消息交给TaskQueue，由worker进行处理
func (mh *MsgHandle) SendMsgToTaskQueue(request ziface.IRequest) {
	//根据ConnID来分配当前的连接该由哪个worker负责处理
	//轮询的平均分配法则
	workerID := request.GetConnection().GetConnID() % mh.WorkerPoolSize
	fmt.Println("Add ConnID=", request.GetConnection().GetConnID(), " request msgID=", request.GetMsgID(), "to workerID=", workerID)
	//将请求消息发送给对应的任务队列
	mh.TaskQueue[workerID] <- request
}

// StartOneWorker 启动一个worker工作流程
func (mh *MsgHandle) StartOneWorker(workerID int, taskQueue chan ziface.IRequest) {
	fmt.Printf("worker id = %d,is started\n", workerID)
	//阻塞等待队列中的消息
	for {
		select {
		case request := <-taskQueue:
			mh.DoMsgHandler(request)
		}
	}
}

// StartWorkerPool 启动worker工作池
func (mh *MsgHandle) StartWorkerPool() {
	//遍历需要启动的worker数量，依次启动
	for i := 0; i < int(mh.WorkerPoolSize); i++ {
		//1个worker被启动，给当前worker对应的任务队列开辟空间
		mh.TaskQueue[i] = make(chan ziface.IRequest, utils.GlobalObject.MaxWorkerTaskLen)
		//启动当前worker，阻塞等待对应的消息队列是否有消息传递进来
		go mh.StartOneWorker(i, mh.TaskQueue[i])
	}
}

// DoMsgHandler 以非阻塞方式调用处理方法处理消息
func (mh *MsgHandle) DoMsgHandler(request ziface.IRequest) {
	handler, ok := mh.Apis[request.GetMsgID()]
	if !ok {
		fmt.Printf("api msgId = %d,is not FOUND\n", request.GetMsgID())
		return
	}
	//执行对应的处理方法
	handler.PreHandle(request)
	handler.Handle(request)
	handler.PostHandle(request)
}

// AddRouter 添加msgId对应的路由器处理者
func (mh *MsgHandle) AddRouter(msgId uint32, router ziface.IRouter) {
	//1.判断当前msg绑定的api处理方法是否已经存在
	if _, ok := mh.Apis[msgId]; ok {
		panic("repeated api,msgId = " + strconv.Itoa(int(msgId)))
	}
	//2.添加msg与api的绑定关系
	mh.Apis[msgId] = router
	fmt.Println("add api msgId =", msgId)
}
